package com.dd.cloud.common.utils;

import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.dd.cloud.common.constants.FileConstants;
import com.dd.cloud.common.enums.ZkExceptionEnum;
import com.dd.cloud.common.exception.ZekeException;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Arrays;

/**
 * @author zk
 */
@Component
@Slf4j
public class UploadUtil {

    /**
     * 支持 单文件 图片上传
     *
     * @param file 文件
     * @return
     */
    public static String uploadImage(MultipartFile file, FastFileStorageClient storageClient) {
        try {
            //校验格式
            String contentType = file.getContentType();
            log.info("文件格式:{}", contentType);
            if (!Arrays.asList(FileConstants.Format.IMG).contains(contentType)) {
                throw new ZekeException(ZkExceptionEnum.CONTENT_TYPE_ERROE);
            }
            //校验内容
            BufferedImage image = ImageIO.read(file.getInputStream());
            if (image == null) {
                throw new ZekeException(ZkExceptionEnum.INVALID_IMAGE_ERROE);
            }
            //上传到FastDFS
            String extension = StringUtils.substringAfterLast(file.getOriginalFilename(), ".");
            StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), extension, null);
            log.info("文件上传地址:{}", storePath.getFullPath());
            //返回路径
            return /* "http://image.leyou.com/" + */storePath.getFullPath();
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new ZekeException(ZkExceptionEnum.UPLOAD_FAILED_ERROE);
        }
    }

    /**
     * 支持 单文件 文件上传
     *
     * @param base64
     * @return
     */
    public static String uploadImage(String base64,FastFileStorageClient storageClient) {
        log.info("base64:{}", base64);
        String extension = "";
        try {
            if (base64.contains("data:image/jpeg;base64,")) {
                base64 = base64.replace("data:image/jpeg;base64,", "");
                extension = "jpg";
            } else if (base64.contains("data:image/jpg;base64,")) {
                base64 = base64.replace("data:image/jpg;base64,", "");
                extension = "jpg";
            } else if (base64.contains("data:image/png;base64,")) {
                base64 = base64.replace("data:image/png;base64,", "");
                extension = "png";
            }
            log.info("base64:{}", base64);
            byte[] bytes = new BASE64Decoder().decodeBuffer(base64.trim());
            ByteArrayInputStream is = new ByteArrayInputStream(bytes);
            //上传到FastDFS
            StorePath storePath = storageClient.uploadFile(is, is.available(), extension, null);
            log.info("文件上传地址:{}", storePath.getFullPath());
            //返回路径
            return storePath.getFullPath();
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new ZekeException(ZkExceptionEnum.UPLOAD_FAILED_ERROE);
        }
    }

    /**
     * 支持 单文件 文件上传
     *
     * @param base64
     * @return
     */
    public static String uploadFile(String base64, String extension, FastFileStorageClient storageClient) {
        log.info("base64:{}", base64);
        try {
            log.info("base64:{}", base64);
            byte[] bytes = new BASE64Decoder().decodeBuffer(base64.trim());
            ByteArrayInputStream is = new ByteArrayInputStream(bytes);
            //上传到FastDFS
            StorePath storePath = storageClient.uploadFile(is, is.available(), extension, null);
            log.info("文件上传地址:{}", storePath.getFullPath());
            //返回路径
            return storePath.getFullPath();
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new ZekeException(ZkExceptionEnum.UPLOAD_FAILED_ERROE);
        }
    }

    /**
     * 支持 单文件 文件上传
     *
     * @param is
     * @return
     */
    public static String uploadImage(InputStream is,FastFileStorageClient storageClient) {
        String extension = FileConstants.Format.DEFAULT_IMG;
        //上传到FastDFS
        StorePath storePath = null;
        try {
            storePath = storageClient.uploadFile(is, is.available(), extension, null);
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
        log.info("文件上传地址:{}", storePath.getFullPath());
        //返回路径
        return storePath.getFullPath();
    }


    /**
     * 支持 单文件 图片上传
     *
     * @return
     */
    public static String uploadImageCompress(MultipartFile file, FastFileStorageClient storageClient) {
        if (file == null) {
            throw new ZekeException(400, "文件不能为空");
        }
        if (!Arrays.asList(FileConstants.Format.IMG).contains(file.getContentType())) {
            throw new ZekeException(400, "暂不支持该图片格式!");
        }
        if (file.getSize() > FileConstants.Size.CEILING) {
            throw new ZekeException(400, "图片超过10mb,上传失败!");
        }
        try {
            //文件后缀
            String extension = StringUtils.substringAfterLast(file.getOriginalFilename(), ".");
            InputStream is;
            if (file.getSize() >= FileConstants.Size.COMPRESS) {
                //压缩图片
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                Thumbnails.of(file.getInputStream()).scale(1.00f).outputQuality(0.10f).outputFormat(extension).toOutputStream(baos);
                is = new ByteArrayInputStream(baos.toByteArray());
            } else {
                is = file.getInputStream();
            }
            //上传到FastDFS
            StorePath storePath = storageClient.uploadFile(is, is.available(), extension, null);
            log.info("文件上传地址:{}", storePath.getFullPath());
            //返回路径
            return /* "http://image.leyou.com/" + */storePath.getFullPath();
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new ZekeException(ZkExceptionEnum.UPLOAD_FAILED_ERROE);
        }
    }

    /**
     * 支持 单文件 图片上传
     *
     * @return
     */
    public static String[] uploadImagesCompress(MultipartFile[] files, FastFileStorageClient storageClient) {
        if (files == null) {
            throw new ZekeException(400, "文件数组不能为空");
        }
        String[] paths = new String[files.length];
        for (int i = 0; i < files.length; i++) {
            if (!Arrays.asList(FileConstants.Format.IMG).contains(files[i].getContentType())) {
                throw new ZekeException(400, "暂不支持该图片格式!");
            }
            if (files[i].getSize() > FileConstants.Size.CEILING) {
                throw new ZekeException(400, "图片超过10mb,上传失败!");
            }
            try {
                //文件后缀
                String extension = StringUtils.substringAfterLast(files[i].getOriginalFilename(), ".");
                InputStream is;
                if (files[i].getSize() >= FileConstants.Size.COMPRESS) {
                    //压缩图片
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    Thumbnails.of(files[i].getInputStream()).scale(1.00f).outputQuality(0.10f).outputFormat(extension).toOutputStream(bos);
                    is = new ByteArrayInputStream(bos.toByteArray());
                } else {
                    is = files[i].getInputStream();
                }
                //上传到FastDFS
                StorePath storePath = storageClient.uploadFile(is, is.available(), extension, null);
                log.info("文件上传地址:{}", storePath.getFullPath());
                paths[i] = storePath.getFullPath();
            } catch (Exception e) {
                log.error("文件上传失败", e);
                throw new ZekeException(ZkExceptionEnum.UPLOAD_FAILED_ERROE);
            }
        }
        return paths;
    }

    /**
     * 支持 单文件 图片上传
     *
     * @return
     */
    public static String uploadImageCompress(byte[] bytes,FastFileStorageClient storageClient) {
        if (bytes == null) {
            throw new ZekeException(400, "字节数组不能为空");
        }
        try {
            InputStream is = new ByteArrayInputStream(bytes);
            if (is.available() > FileConstants.Size.CEILING) {
                throw new ZekeException(400, "图片超过10mb,上传失败!");
            }
            InputStream iss = null;
            //超过512kb
            if (is.available() > FileConstants.Size.COMPRESS) {
                //压缩图片
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                Thumbnails.of(is).scale(1.00f).outputQuality(0.10f).outputFormat(FileConstants.Format.DEFAULT_IMG).toOutputStream(bos);
                iss = new ByteArrayInputStream(bos.toByteArray());
            }
            //上传到FastDFS
            StorePath storePath = storageClient.uploadFile(iss == null ? is : iss, iss == null ? is.available() : iss.available(), FileConstants.Format.DEFAULT_IMG, null);
            log.info("文件上传地址:{}", storePath.getFullPath());
            //返回路径
            return storePath.getFullPath();
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new ZekeException(ZkExceptionEnum.UPLOAD_FAILED_ERROE);
        }
    }

    /**
     * 支持 单文件 文件上传
     *
     * @param file 文件
     * @return
     */
    public static String uploadFile(MultipartFile file, FastFileStorageClient storageClient) {
        if (file == null) {
            throw new ZekeException(ZkExceptionEnum.FILE_NOT_BE_NULL);
        }
        try {
            //文件后缀
            String extension = StringUtils.substringAfterLast(file.getOriginalFilename(), ".");
            //上传到FastDFS
            StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(), extension, null);
            log.info("文件上传地址:{}", storePath.getFullPath());
            //返回路径
            return storePath.getFullPath();
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new ZekeException(ZkExceptionEnum.UPLOAD_FAILED_ERROE);
        }
    }

    /**
     * 支持 单文件 文件上传
     *
     * @param bytes  文件字节数据
     * @param suffix 文件后缀
     * @return
     */
    public static String uploadFile(byte[] bytes, String suffix,FastFileStorageClient storageClient) {
        if (bytes == null) {
            throw new ZekeException(ZkExceptionEnum.FILE_NOT_BE_NULL);
        }
        try {
            log.info("文件后缀:{}", suffix);
            //字节数据转输入流
            ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
            //上传到FastDFS
            StorePath storePath = storageClient.uploadFile(bis, bis.available(), suffix, null);
            log.info("文件上传地址:{}", storePath.getFullPath());
            //返回路径
            return storePath.getFullPath();
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new ZekeException(ZkExceptionEnum.UPLOAD_FAILED_ERROE);
        }
    }

    /**
     * 删除文件
     *
     * @param addr
     */
    public static void delFile(String addr,FastFileStorageClient storageClient) {
        try {
            StorePath storePath = StorePath.praseFromUrl(addr);
            log.info("addr:{}", addr);
            log.info("group:{}", storePath.getGroup());
            log.info("fullPath:{}", storePath.getFullPath());
            log.info("path:{}", storePath.getPath());
            storageClient.deleteFile(storePath.getGroup(), storePath.getPath());
        } catch (Exception e) {
            log.error("文件删除失败:", e);
        }
    }

    /**
     * 支持 单文件 多文件上传
     *
     * @param files 文件数组
     * @return
     */
    public static String[] uploadFiles(MultipartFile[] files, FastFileStorageClient storageClient) {
        if (files == null) {
            throw new ZekeException(ZkExceptionEnum.FILES_NOT_BE_NULL);
        }
        String[] paths = new String[files.length];
        try {
            for (int i = 0; i < files.length; i++) {
                //文件后缀
                String extension = StringUtils.substringAfterLast(files[i].getOriginalFilename(), ".");
                if (extension == null || extension.isEmpty()) {
                    extension = StringUtils.substringAfterLast(files[i].getName(), ".");
                }
                log.info("文件后缀:{}", extension);
                log.info("文件大小:{}", files[i].getSize());
                //上传到FastDFS
                StorePath storePath = storageClient.uploadFile(files[i].getInputStream(), files[i].getSize(), extension, null);
                log.info("文件上传地址:{}", storePath.getFullPath());
                paths[i] = storePath.getFullPath();
            }
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new ZekeException(ZkExceptionEnum.UPLOAD_FAILED_ERROE);
        }
        return paths;
    }


    /**
     * 文件预览
     *
     * @param fileName 文件全路径
     * @param response
     */
    public static void preview(String fileName, HttpServletResponse response) {
    }

    /**
     * 文件下载
     *
     * @param fileUrl  文件全路径
     * @param name     文件名
     * @param response
     * @throws IOException
     */
    public static void downloadFile(String fileUrl, String name, HttpServletResponse response) throws IOException {
        // 以流的形式下载文件。
        InputStream in = null;
        OutputStream os = null;
        try {
            File file = new File(fileUrl);
            in = new BufferedInputStream(new FileInputStream(fileUrl));
            byte[] buffer = new byte[in.available()];
            in.read(buffer);
            // 清空response
            response.reset();
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" + name);
            response.addHeader("Content-Length", "" + file.length());
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/octet-stream");
            os = new BufferedOutputStream(response.getOutputStream());
            os.write(buffer);
            os.flush();
        } catch (Exception ex) {
            log.error("文件下载失败，异常信息=[{}]", ex);
            ex.printStackTrace();
        } finally {
            in.close();
            os.close();
        }
    }

    public static void downloadNetFileToClient(HttpServletResponse response, String fileUrl, String fileName) {
        URL url;
        URLConnection conn;
        InputStream inputStream = null;
        try {
            // 这里填文件的url地址
            url = new URL(fileUrl);
            conn = url.openConnection();
            inputStream = conn.getInputStream();
            response.setCharacterEncoding("utf-8");
            response.setContentType(conn.getContentType());
            // 使用URLEncoder.encode(fileName, "UTF-8")将文件名设置为UTF-8的编码格式
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            byte[] buffer = new byte[1024];
            int len;
            OutputStream outputStream = response.getOutputStream();
            while ((len = inputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, len);
            }
        } catch (IOException e) {
            // 如果发生异常，返回自定义的下载失败的提示信息
            e.printStackTrace();
            throw new ZekeException(ZkExceptionEnum.FILE_DOWNLOAD_ERR);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
